
#include "ASpriteContainer.h"
#include "ASprite.h"
#include "AString.h"
#include "AStage.h"
#include "AStageLayer.h"

#define REMOVE_SPRITES_COUNT_PER_UPDATE	4

CASpriteContainer::CASpriteContainer()
{
}

CASpriteContainer::~CASpriteContainer()
{
	_Assert(_spritesWillBeRemoved.count() <= 0);
	_Assert(_spritesWillBeAttached.count() <= 0);
}

void CASpriteContainer::_addSprite(CASprite* pspr)
{
	CAString k = pspr->getTextureName();
	_Assert(k.length() > 0);

	this->_addNamedSprite(pspr);
#if 1
	CCSpriteBatchNode* p = pspr->layer()->stage()->getSpriteGroup(k);
	p->addChild(pspr, (int)(pspr->getZOrder() * 100.0f), pspr->getTag());
#else
	pspr->layer()->stage()->addChild(pspr, (int)(pspr->getZOrder() * 100.0f), pspr->getTag());
#endif
}

void CASpriteContainer::addSprite(CASprite * pspr, bool bNow)
{
	if (bNow)
	{
		_addSprite(pspr);
	}
	else
	{
		_spritesWillBeAttached.addObject(pspr);
	}
}

void CASpriteContainer::removeSprite(CASprite* pspr)
{
	//_Assert(null == _spritesWillBeRemoved.objectForKey(pspr));
	_spritesWillBeRemoved.addObject(pspr);
}

void _name_group(const CAString& name, strings& names)
{
	strings names1;
	CAStringUtils::split(name, "-", names);
	names.push_back(NAMED_GROUP_ALL);
}

void CASpriteContainer::_addNamedSprite(CASprite* pspr)
{
	strings names;
	_name_group(pspr->getGroupName(), names);

	size_t i;
	for (i = 0; i < names.size(); i++)
	{
		CAString name = names[i];
		if (name.length() > 0)
		{
			CCArray* pary = (CCArray*)_spritesNamed.objectForKey(name);
			if (null == pary)
			{
				pary = CCArray::array();
				_spritesNamed.setObject(pary, name);
			}
			pary->addObject(pspr);
		}
	}
}

void CASpriteContainer::_removeNamedSprite(CASprite* pspr)
{
	strings names;
	_name_group(pspr->getGroupName(), names);

	size_t i;
	for (i = 0; i < names.size(); i++)
	{
		CAString name = names[i];
		CCArray* pary = (CCArray*)_spritesNamed.objectForKey(name);
		_Assert(null != pary);
		pary->removeObject(pspr);
	}
}

CCArray* CASpriteContainer::_getNamedSprites(const char* name)
{
	CCArray* pary = (CCArray*)_spritesNamed.objectForKey(name);
	return pary;
}

size_t CASpriteContainer::_getNamedSpritesCount(const char* name)
{
	CCArray* pary = (CCArray*)_spritesNamed.objectForKey(name);
	if (null != pary) return pary->count();
	return 0;
}

CASprite* CASpriteContainer::_getNamedSprite(const char* name, unsigned int index)
{
	CCArray* pary = (CCArray*)_spritesNamed.objectForKey(name);
	_Assert(null != pary);
	if (index >= 0 && index < pary->count())
		return (CASprite*)(pary->objectAtIndex(index));
	return null;
}


int CASpriteContainer::_removeDiedSprites()
{
	CASprite* pspr;
	int n = 0;
	while (true)
	{
		pspr = _spritesWillBeRemoved.removeBegin();
		if (null != pspr)
		{
			_removeNamedSprite(pspr);
			pspr->getParent()->removeChild(pspr, true);
			n++;
		}
		else
		{
			break;
		}
	}
	return n;
}

void CASpriteContainer::_addScheduledSprites()
{
	do
	{
		CASprite* pspr = _spritesWillBeAttached.peekBegin();
		if (null == pspr)
			break;

		_addSprite(pspr);

		CASprite* psprRemoved = _spritesWillBeAttached.removeBegin();
		_Assert(psprRemoved == pspr);
	}
	while (true);
}

void CASpriteContainer::onEnter()
{
}

void CASpriteContainer::onUpdate()
{
	_removeDiedSprites();
	_addScheduledSprites();
}

void CASpriteContainer::onExit()
{
	_addScheduledSprites();
	_removeDiedSprites();
}
